package org.zebra.common.util;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.MD5;
import org.springframework.lang.Nullable;

import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * Id工具类
 *
 * @author zhanghongbin
 */
public class IdPlusUtil extends cn.hutool.core.util.IdUtil {

    private IdPlusUtil() {}

    public static long toLongId(String id) {
        MessageDigest md5Digest = new MD5().getDigest();
        byte[] md5hash;
        synchronized (md5Digest) {
            md5hash = md5Digest.digest(id.getBytes(Charset.forName("UTF-8")));
            md5Digest.reset();
        }
        long hash = 0;
        for (int i = 0; i < 8; i++) {
            // FF会存在负数情况
            // hash = hash << 8 | md5hash[i] & 0x00000000000000FFL;
            hash = hash << 8 | md5hash[i] & 0x000000000000007D;
        }
        return hash;
    }

    /**
     * 获得20位有序时间单号（可读的时间有序、纯数字、20位）
     *
     * @return 20位有序时间单号
     */
    public static String getDateOrderNo() {
        return getDateOrderNo(null);
    }

    /**
     * 获得有序时间单号（可读的时间有序、纯数字、默认20位）
     *
     * @param length 时间单号长度（可以为null，最小20位，最长36位）
     * @return 有序时间单号
     */
    public static String getDateOrderNo(@Nullable Integer length) {
        StringBuilder orderNo = new StringBuilder();
        orderNo.append(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(LocalDateTime.now()));
        String snowflakeNextIdStr = cn.hutool.core.util.IdUtil.getSnowflakeNextIdStr();
        int subLength = snowflakeNextIdStr.length() - 3;
        if (length != null && length > 20) {
            subLength = subLength - (length - 20);
        }

        return orderNo.append(snowflakeNextIdStr.substring(subLength)).toString();
    }

    /**
     * 获得随机生成n位数字编码（纯数字）
     *
     * @param length 长度
     * @return 对应长度的数字编码（纯数字）
     */
    public static String getRandomNumberCode(int length) {
        // 字符源，可以根据需要删减
        String randomCodeSource = "0123456789";
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < length; i++) {
            // 循环随机获得当次字符
            code.append(randomCodeSource.charAt((int) Math.floor(Math.random() * randomCodeSource.length())));
        }

        return code.toString();
    }

    /**
     * 获得随机生成n位字符编码（数字+字母）
     *
     * @param length 长度
     * @return 对应长度的字符编码（数字+字母）
     */
    public static String getRandomCode(int length) {
        // 字符源，可以根据需要删减
        String randomCodeSource = "23456789abcdefghgklmnpqrstuvwxyzABCDEFGHGKLMNPQRSTUVWXYZ"; // 去掉1和i ，0和o
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < length; i++) {
            // 循环随机获得当次字符
            code.append(randomCodeSource.charAt((int) Math.floor(Math.random() * randomCodeSource.length())));
        }

        return code.toString();
    }

    /**
     * 获得随机生成n位大写字符编码（数字+大写字母）
     *
     * @param length 长度
     * @return 对应长度的大写字符编码（数字+大写字母）
     */
    public static String getRandomCodeToUpperCase(int length) {
        // 字符源，可以根据需要删减
        String randomCodeSource = "23456789ABCDEFGHGKLMNPQRSTUVWXYZ"; // 去掉1和i ，0和o
        StringBuilder code = new StringBuilder();
        for (int i = 0; i < length; i++) {
            // 循环随机获得当次字符
            code.append(randomCodeSource.charAt((int) Math.floor(Math.random() * randomCodeSource.length())));
        }

        return code.toString();
    }

    /**
     * 代表数字位数
     */
    public static int NUM_LENGTH = 2;

    public static final char LETTER = 'Z';

    /**
     * 根据前一个code，获取同级下一个code
     * 例如:当前最大code为D01A04，下一个code为：D01A05
     *
     * @param code
     * @return
     */
    public static synchronized String getSerialCode(String code) {
        String newcode = "";
        if (StrUtil.isEmpty(code)) {
            String zimu = "A";
            String num = getStrNum(1);
            newcode = zimu + num;
        } else {
            String beforeCode = code.substring(0, code.length() - 1 - NUM_LENGTH);
            String afterCode = code.substring(code.length() - 1 - NUM_LENGTH, code.length());
            char afterCodeZimu = afterCode.substring(0, 1).charAt(0);
            Integer afterCodeNum = Integer.parseInt(afterCode.substring(1));
            String nextNum = "";
            char nextZimu = 'A';
            // 先判断数字等于999*，则计数从1重新开始，递增
            if (afterCodeNum == getMaxNumByLength(NUM_LENGTH)) {
                nextNum = getNextStrNum(0);
            } else {
                nextNum = getNextStrNum(afterCodeNum);
            }
            // 先判断数字等于999*，则字母从A重新开始,递增
            if (afterCodeNum == getMaxNumByLength(NUM_LENGTH)) {
                nextZimu = getNextZiMu(afterCodeZimu);
            } else {
                nextZimu = afterCodeZimu;
            }

            // 例如Z99，下一个code就是Z99A01
            if (LETTER == afterCodeZimu && getMaxNumByLength(NUM_LENGTH) == afterCodeNum) {
                newcode = code + (nextZimu + nextNum);
            } else {
                newcode = beforeCode + (nextZimu + nextNum);
            }
        }
        return newcode;
    }

    /**
     * 根据父亲code,获取下级的下一个code
     * <p>
     * 例如：父亲CODE:A01
     * 当前CODE:A01B03
     * 获取的code:A01B04
     *
     * @param parentCode 上级code
     * @param localCode  同级code
     * @return
     */
    public static synchronized String getSubSerialCode(String parentCode, String localCode) {
        if (localCode != null && localCode != "") {
            return getSerialCode(localCode);
        } else {
            parentCode = parentCode + "A" + getNextStrNum(0);
        }
        return parentCode;
    }

    /**
     * 将数字前面位数补零
     *
     * @param num
     * @return
     */
    private static String getNextStrNum(int num) {
        return getStrNum(getNextNum(num));
    }

    /**
     * 将数字前面位数补零
     *
     * @param num
     * @return
     */
    private static String getStrNum(int num) {
        String s = String.format("%0" + NUM_LENGTH + "d", num);
        return s;
    }

    /**
     * 递增获取下个数字
     *
     * @param num
     * @return
     */
    private static int getNextNum(int num) {
        num++;
        return num;
    }

    /**
     * 递增获取下个字母
     *
     * @param zimu 当前字母
     * @return 下一个字母
     */
    private static char getNextZiMu(char zimu) {
        if (zimu == LETTER) {
            return 'A';
        }
        zimu++;
        return zimu;
    }

    /**
     * 根据数字位数获取最大值
     *
     * @param length
     * @return
     */
    private static int getMaxNumByLength(int length) {
        if (length == 0) {
            return 0;
        }
        StringBuilder maxNum = new StringBuilder();
        for (int i = 0; i < length; i++) {
            maxNum.append("9");
        }
        return Integer.parseInt(maxNum.toString());
    }

    public static String[] cutYouBianCode(String code) {
        if (code == null || StrUtil.isEmpty(code)) {
            return null;
        } else {
            // 获取标准长度为numLength+1,截取的数量为code.length/numLength+1
            int c = code.length() / (NUM_LENGTH + 1);
            String[] cutcode = new String[c];
            for (int i = 0; i < c; i++) {
                cutcode[i] = code.substring(0, (i + 1) * (NUM_LENGTH + 1));
            }
            return cutcode;
        }
    }
}
